// +build !no_file_scan

package exploit

import (
	"fmt"
	"github.com/cdk-team/CDK/conf"
	"github.com/cdk-team/CDK/pkg/cli"
	"github.com/cdk-team/CDK/pkg/plugin"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

func SearchLocalFileText(StartDir string) {
	_ = filepath.Walk(StartDir, func(path string, info os.FileInfo, err error) error {

		// broken soft-link file will trigger panic in os.Stat().xxx()
		defer func() {
			if err := recover(); err != nil {

			}
		}()

		fileInfo, _ := os.Stat(path)

		// skip soft-link
		//if util.IsSoftLink(path) {
		//	println("skip ln:", path)
		//	return nil
		//}
		// drop dir, only scan files
		if fileInfo.IsDir() {
			return nil
		}
		// skip large file
		if fileInfo.Size() > conf.ScanFileTextConf.MaxFileByte {
			return filepath.SkipDir
		}
		// skip executable file
		if conf.ScanFileTextConf.SkipExecutableFile && strings.Contains(fileInfo.Mode().String(), "x") {
			return filepath.SkipDir
		}

		// read file text
		data, err := ioutil.ReadFile(path)
		if err != nil {
			//log.Fatal(err) //ignore fatal errors
		}

		// apply regexp match
		for k, v := range conf.ScanFileTextConf.RegexList {
			pattern := regexp.MustCompile(v)
			params := pattern.FindAllStringSubmatch(string(data), -1)
			for _, matched := range params {
				fmt.Printf("\nfound %s in: %s\n%s\n", k, path, matched)
			}
		}

		return nil
	})
}

// plugin interface
type FileScanS struct{}

func (p FileScanS) Desc() string {
	return "search AK/Secrets from input dir, usage: cdk run ak-leakage <dir>"
}
func (p FileScanS) Run() bool {
	if len(cli.Args["<args>"].([]string)) != 1 {
		log.Println("Invalid input args.")
		log.Fatal(p.Desc())
	}
	path := cli.Args["<args>"].([]string)[0]
	log.Println("searching secrets in ", path)
	SearchLocalFileText(path)
	log.Println("finished.")
	return true
}

func init() {
	exploit := FileScanS{}
	plugin.RegisterExploit("ak-leakage", exploit)
}
